#pragma once
#include "../Logic/ScriptParser.h"
#include "../Logic/ScriptFileReader.h"

namespace Testing
{
   namespace Scripts
   {
      /// <summary>Occurs when a validation test fails</summary>
      class LogicExport ValidationException : public ExceptionBase
      {
      public:
         /// <summary>Create an ValidationException</summary>
         /// <param name="src">Location of throw</param>
         /// <param name="msg">Message</param>
         ValidationException(wstring  src, GuiString msg) 
            : ExceptionBase(src, GuiString(L"Validation failed: ") + msg)
         {}

         /// <summary>Create an ValidationException</summary>
         /// <param name="src">Location of throw</param>
         /// <param name="msg">Message</param>
         /// <param name="orig">Original value</param>
         /// <param name="copy">Validation copy value</param>
         ValidationException(wstring  src, GuiString msg, GuiString orig, GuiString copy) 
            : ExceptionBase(src, VString(L"Validation failed: %s\n  Original: '%s'\n  Copy: '%s'", msg.c_str(), orig.c_str(), copy.c_str()) )
         {}
      };

      /// <summary>Validates the code and text produced by the script compiler</summary>
      class LogicExport ScriptValidator
      {
         // ------------------------ TYPES --------------------------
      private:

         // --------------------- CONSTRUCTION ----------------------

      public:
         ScriptValidator(Path file);
         virtual ~ScriptValidator();

         DEFAULT_COPY(ScriptValidator);	// Default copy semantics
         DEFAULT_MOVE(ScriptValidator);	// Default move semantics

         // ------------------------ STATIC -------------------------
      private:
         static void       CompileScript(ScriptFile& s, Path truePath);
         static LineArray  GetAllLines(const CommandList& commands);
         static ScriptFile ReadScript(Path truePath, Path displayPath, bool dropJMPs);
         static void       PrintTree(const CommandList& list);

         // --------------------- PROPERTIES ------------------------

         // ---------------------- ACCESSORS ------------------------			
      
         // ----------------------- MUTATORS ------------------------
      public:
         void  Print();
         bool  Validate();

         // -------------------- REPRESENTATION ---------------------

      private:
         Path  FullPath;
      };

      /// <summary>Validates the script text generated by the script translator</summary>
      class LogicExport ScriptTextValidator
      {
         // ------------------------ TYPES --------------------------
      private:

         // --------------------- CONSTRUCTION ----------------------
      public:

         // ------------------------ STATIC -------------------------
      public:
         static bool  Compare(const LineArray& in, const LineArray& out);
         static bool  Compare(const ScriptFile& in, const ScriptFile& out);

      private:
         static bool  Compare(const ScriptVariable& in, const ScriptVariable& out);
         static bool  Compare(UINT line, const ScriptCommand& in, const ScriptCommand& out);
         static bool  Compare(UINT line, UINT param, const ScriptParameter& in, const ScriptParameter& out);

         static ValidationException  TextMismatch(const GuiString& src, const GuiString& prop, const GuiString& a, const GuiString& b);
         static ValidationException  TextMismatch(const GuiString& src, const GuiString& prop, int a, int b);

         // --------------------- PROPERTIES ------------------------

         // ---------------------- ACCESSORS ------------------------			

         // ----------------------- MUTATORS ------------------------
      
         // -------------------- REPRESENTATION ---------------------

      };

      /// <summary>Validates the script XML generated by the script compiler</summary>
      class LogicExport ScriptCodeValidator
      {
         // ------------------------ TYPES --------------------------
      private:
         class ScriptReader : public ScriptValueReader
         {
            // --------------------- CONSTRUCTION ----------------------
         public:
            ScriptReader(StreamPtr in) : ScriptValueReader(in)
            {
               LoadDocument();   // Parse document on construction
            }

            // --------------------- PROPERTIES ------------------------

            // ---------------------- ACCESSORS ------------------------			

            // ----------------------- MUTATORS ------------------------
         public:
            /// <summary>Retrieves the child of a node</summary>
            /// <param name="parent">The node</param>
            /// <param name="index">Zero-based index</param>
            /// <param name="help">Meaning of node</param>
            /// <returns>Child node</returns>
            /// <exception cref="Logic::ArgumentNullException">Parent is null</exception>
            /// <exception cref="Logic::FileFormatException">Invalid index</exception>
            /// <exception cref="Logic::ComException">COM Error</exception>
            XmlNodePtr  GetChild(XmlNodePtr& parent, UINT index, const WCHAR* help)
            {
               return ScriptValueReader::GetChild(parent, index, help);
            }
         };

         // --------------------- CONSTRUCTION ----------------------
      public:
         ScriptCodeValidator(StreamPtr orig, StreamPtr copy);

         // ------------------------ STATIC -------------------------
      private:
         static ValidationException  CodeMismatch(const GuiString& src, const GuiString& prop, const ParameterValue& a, const ParameterValue& b);
         static ValidationException  CodeMismatch(const GuiString& src, const GuiString& prop, const GuiString& a, const GuiString& b);
         static ValidationException  CodeMismatch(const GuiString& src, const GuiString& prop, int a, int b);

         // --------------------- PROPERTIES ------------------------

         // ---------------------- ACCESSORS ------------------------			

         // ----------------------- MUTATORS ------------------------
      public:
         bool  Compare();

      private:
         bool  Compare(XmlNodePtr parent_in, XmlNodePtr parent_out, UINT index, GuiString help);
         void  CompareArguments();
         void  CompareCommands(CommandType cmdType);
         bool  CompareSize(XmlNodePtr parent_in, XmlNodePtr parent_out, UINT index, GuiString help);
         void  CompareVariables();
         bool  IsCommentedLabel(XmlNodePtr in_cmd, XmlNodePtr out_cmd, const GuiString& line);

         // -------------------- REPRESENTATION ---------------------
      private:
         ScriptReader   In, Out;
         VariableArray  InVars, OutVars;
         GameVersion    Version;
      };

   }
}

using namespace Testing::Scripts;
